package com.myrpc.provider.netty;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.myrpc.common.MyMessageDecoder;
import com.myrpc.common.MyMessageEncoder;
import com.myrpc.provider.registry.ServiceRegistry;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;

@Component
public class NettyServer implements InitializingBean{
	
	@Autowired
	ServiceRegistry serviceRegistry;
	
	ServerBootstrap bootstrap =  new ServerBootstrap();
	
	EventLoopGroup boss = new NioEventLoopGroup();
	EventLoopGroup worker = new NioEventLoopGroup();
	
    @Value("${rpc.server.address}")
    private String rpcAddress;
	
	public void start() {
		
		new Thread(()->{
			try {
				
				bootstrap.group(boss, worker);
				//设置ServerSocketChannel工厂类
				bootstrap.channel(NioServerSocketChannel.class);
				
				//初始化管道 工厂类
				bootstrap.childHandler(new ChannelInitializer<Channel>() {

					@Override
					protected void initChannel(Channel ch) throws Exception {
						// 客户端的逻辑
						ch.pipeline().addLast("frameDecoder",new LengthFieldBasedFrameDecoder(65535,0,3,0,3));
						//在ByteBuf之前增加3个字节的消息长度字段
						ch.pipeline().addLast("frameEncoder",new LengthFieldPrepender(3));

						
						ch.pipeline().addLast(new MyMessageEncoder());
						ch.pipeline().addLast(new MyMessageDecoder());
						
						ch.pipeline().addLast("serverHandler", new ServerHandler());
					}
					
				});
				
				bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
				
				bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
				
				String[] str  = rpcAddress.split(":");
				
				ChannelFuture channelFuture = bootstrap.bind(str[0],Integer.parseInt(str[1]))
						//Waits for this future until it is done and rethrows the cause of the failure if this future failed.
						.sync();
				System.out.println("server start ...");
				Channel channel = channelFuture.channel();
				
				serviceRegistry.register(rpcAddress);
				//优雅等待服务关闭,个人理解：主线程执行到这里就 wait 子线程结束，即 closeFuture()是开启了一个channel的监听器，负责监听channel是否关闭的状态
				channel.closeFuture().sync();
				
				}catch (Exception e) {
					// TODO: handle exception
				}finally {
					//优雅关闭，ShutdownGracefully()不但断开所以连接，而且将其中的内存清理掉。
					boss.shutdownGracefully();
					worker.shutdownGracefully();
				}
		}).start();
		
		
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		
		this.start();
		
	}
	
	

}
